/*
 * Copyright Hundsun Technologies Inc. All Rights Reserved.
 */

package contract

//store package store the world - state data
import (
	"sync"

	"hundsun.com/hsl/hschain/common/types"
)

const (
	// MaxHandleCache 最大缓存handler数
	MaxHandleCache = 256
	// MaxPreInitSize 每个preInit驱动最大size
	MaxPreInitSize = 100
	// ExtraPreInitSize 预留preInit空位，避免chan阻塞
	ExtraPreInitSize = 2
)

// NewContract DriverCreate defines a drivercreate function
type NewContract func() Contract

type driverHeight struct {
	contrct NewContract
	height  uint64
}

var (
	contractDrivers = make(map[string]*driverHeight)
	contractHandles = make(map[string]*DriverChannel, MaxHandleCache)
)

// DriverChannel driver chan
type DriverChannel struct {
	active chan Contract // 目前可供使用的driver对象
	busy   chan Contract // 目前使用中的driver对象

	driverChannelMutex *sync.Mutex
}

// NewDriverChannel 新建一个driver channel
func NewDriverChannel() *DriverChannel {
	d := &DriverChannel{}
	d.active = make(chan Contract, MaxPreInitSize+(ExtraPreInitSize*2))
	d.busy = make(chan Contract, MaxPreInitSize+ExtraPreInitSize)
	d.driverChannelMutex = &sync.Mutex{}
	return d
}

// Register register dcriver height in name
// param name    每个执行器名字全局唯一
// param preInit 主要用于缓存大的初始化过大的执行器资源，如jvm
// param height  执行器起作用高度
func Register(name string, create NewContract, preInit, bSysContract bool, height uint64) {
	if create == nil {
		panic("Execute: Register driver is nil")
	}

	var contractName string
	if bSysContract {
		contractName = types.GenSysContractName(name)
	} else {
		contractName = name
	}

	if _, dup := contractDrivers[contractName]; dup {
		panic("Execute: Register called twice for driver " + name)
	}
	if preInit {
		contractHandles[contractName] = NewDriverChannel()
	}
	exec := &driverHeight{
		contrct: create,
		height:  height,
	}
	contractDrivers[contractName] = exec
}

// LoadDriver load driver
func LoadDriver(name string, height uint64) (driver Contract, err error) {
	contractName := name
	e, ok := contractDrivers[contractName]
	if !ok {
		contractName = types.GenSysContractName(name)
		e, ok = contractDrivers[contractName]
		if !ok {
			return nil, types.ErrNoRegistedDriver
		}
	}
	if height >= e.height {
		if _, ok := contractHandles[contractName]; ok {
			return findIdleHandle(contractName)
		}
		div := e.contrct()
		div.Init()

		return div, nil
	}
	return nil, types.ErrNoRegistedDriver
}

// ClearDriversAndHandlers 清理drivers和handlers，仅供测试用例调用
func ClearDriversAndHandlers() {
	contractDrivers = make(map[string]*driverHeight)
	contractHandles = make(map[string]*DriverChannel, MaxHandleCache)
}

func findIdleHandle(name string) (Contract, error) {
	if div, ok := contractHandles[name]; ok {
		v := div.getActiveDriver()
		if v != nil {
			return v, nil
		}
		// new
		e, ok := contractDrivers[name]
		if !ok {
			return nil, types.ErrNoRegistedDriver
		}

		ct := e.contrct()
		ct.Init()
		div.busy <- ct
		return ct, nil
	}

	return nil, nil
}

// AddDriverHandle 添加driver handler
func AddDriverHandle(name string, contract Contract) {
	if ex, ok := contractHandles[name]; ok {
		driver := <-ex.busy
		ex.active <- driver
		return
	}
}

func (c *DriverChannel) isAllChanBusy() bool {
	return len(c.active)+len(c.busy) >= MaxPreInitSize
}

func (c *DriverChannel) getActiveDriver() Contract {
	c.driverChannelMutex.Lock()
	defer c.driverChannelMutex.Unlock()

	if len(c.active) == 0 && c.isAllChanBusy() {
		driver := <-c.active
		c.busy <- driver
		return driver
	}

	if len(c.active) > 0 {
		driver := <-c.active
		c.busy <- driver
		return driver
	}

	return nil
}
